package com.segi.view.imageview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.segi.view.R;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 签名控件
 *
 * @author liangzx
 * @version 1.0
 * @time 2018-10-19 14:46
 **/
public class SignatureView extends View {

    /**
     * 签名画笔
     */
    private Paint mPaint = new Paint();
    /**
     * 画笔路径
     */
    private Path mPath = new Path();
    private Path mTmpPath = new Path();
    /**
     * 画布
     */
    private Canvas mCacheCanvas;
    /**
     * 签名实时记录
     */
    private Bitmap mCacheBitmap;
    /**
     * 上次保存的签名
     */
    private Bitmap mLastTimeBitmap;
    /**
     * 画笔宽度
     */
    private int mPaintWidth = getResources().getDimensionPixelSize(R.dimen.x3);
    /**
     * 画笔颜色
     */
    private int mPaintColor = Color.BLACK;
    /**
     * 画布背景色
     */
    private int mBGColor = Color.WHITE;
    /**
     * X坐标
     */
    private float mStartX;
    /**
     * Y坐标
     */
    private float mStartY;
    /**
     * 是否正在画
     */
    private boolean mIsPainting = false;
    /**
     * 是否已计算好宽高度
     */
    private boolean mHasSizeChanged = false;
    /**
     * 保存涂鸦操作，便于撤销
     */
    private CopyOnWriteArrayList<Path> mPathStack = new CopyOnWriteArrayList<>();

    public SignatureView(Context context) {
        super(context);
        init(context);
    }

    public SignatureView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public SignatureView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    /**
     * 初始化
     *
     * @param context
     */
    private void init(Context context) {
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Style.STROKE);
        mPaint.setColor(mPaintColor);
        mPaint.setStrokeWidth(mPaintWidth);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mCacheBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);
        mCacheCanvas = new Canvas(mCacheBitmap);
        mCacheCanvas.drawColor(mBGColor);
        if (null != mLastTimeBitmap) {
            mCacheCanvas.drawBitmap(mLastTimeBitmap, 0, 0, mPaint);
            mIsPainting = true;
            invalidate();
        } else {
            mIsPainting = false;
        }
        mHasSizeChanged = true;
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //画此次笔画之前的签名
        canvas.drawBitmap(mCacheBitmap, 0, 0, mPaint);
        //通过画布绘制多点形成的图形
        canvas.drawPath(mPath, mPaint);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                mPath = new Path();
                mTmpPath = new Path();
                float x = event.getX();
                float y = event.getY();
                mStartX = x;
                mStartY = y;
                mPath.moveTo(x, y);
                mTmpPath.moveTo(x, y);
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                mIsPainting = true;
                final float x = event.getX();
                final float y = event.getY();
                final float preX = mStartX;
                final float preY = mStartY;
                final float dx = Math.abs(x - preX);
                final float dy = Math.abs(y - preY);
                // 两点之间的距离大于等于5时，生成贝塞尔绘制曲线
                if (dx >= 10 || dy >= 10) {
                    // 设置贝塞尔曲线的操作点为起点和终点的一半
                    float cX = (x + preX) / 2;
                    float cY = (y + preY) / 2;
                    // 二次贝塞尔，实现平滑曲线；preX, preY为操作点，cX, cY为终点
                    mPath.quadTo(preX, preY, cX, cY);
                    mTmpPath.quadTo(preX, preY, cX, cY);
                    // 第二次执行时，第一次结束调用的坐标值将作为第二次调用的初始坐标值
                    mStartX = x;
                    mStartY = y;
                    invalidate();
                }
                break;
            }
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: {
                mCacheCanvas.drawPath(mPath, mPaint);
                // 把操作记录到加入的堆栈中
                mPathStack.add(mTmpPath);
                mPath.reset();
                invalidate();
                break;
            }
        }
        return true;
    }


    /**
     * 清除
     */
    public void clear() {
        if (null != mCacheCanvas) {
            mLastTimeBitmap = null;
            mIsPainting = false;
            mCacheCanvas.drawColor(mBGColor, PorterDuff.Mode.CLEAR);
            mCacheCanvas.drawColor(mBGColor);
            mPathStack.clear();
            invalidate();
        }
    }

    /**
     * 撤销
     */
    public void undo() {
        if (null != mCacheCanvas) {
            if (null != mPathStack && mPathStack.size() > 0) {
                if (null == mLastTimeBitmap) {
                    mCacheBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);
                    mCacheCanvas = new Canvas(mCacheBitmap);
                    mCacheCanvas.drawColor(mBGColor);
                } else {
                    mCacheCanvas.drawBitmap(mLastTimeBitmap, 0, 0, mPaint);
                }
                mPathStack.remove(mPathStack.size() - 1);
                for (Path item : mPathStack) {
                    mCacheCanvas.drawPath(item, mPaint);
                }
                mCacheCanvas.save();
                mCacheCanvas.restore();
                if (0 == mPathStack.size()) {
                    mIsPainting = false;
                }
                invalidate();
            } else {
                clear();
            }
        }
    }


    /**
     * 保存
     *
     * @param path           保存路径
     * @param needClearBlank 是否需要清除白色边缘
     * @param blankWidth     空白边缘宽度
     */
    public boolean save(String path, boolean needClearBlank, int blankWidth) {
        Bitmap bitmap = mCacheBitmap;
        if (null == bitmap) {
            return false;
        }
        if (needClearBlank) {
            bitmap = clearBlank(bitmap, blankWidth);
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
        byte[] buffer = bos.toByteArray();
        if (buffer != null) {
            File file = new File(path);
            if (file.exists()) {
                file.delete();
            }
            try {
                OutputStream outputStream = new FileOutputStream(file);
                outputStream.write(buffer);
                outputStream.close();
//				if (null != mCacheBitmap) {
//					mCacheBitmap.recycle();
//					mCacheBitmap = null;
//				}
                return true;
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            } finally {
                if (null != bos) {
                    try {
                        bos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return false;
    }

    /**
     * 清楚空白边缘
     *
     * @param bp
     * @param blankWidth
     * @return
     */
    public Bitmap clearBlank(Bitmap bp, int blankWidth) {
        int HEIGHT = bp.getHeight();
        int WIDTH = bp.getWidth();
        int top = 0, left = 0, right = 0, bottom = 0;
        int[] pixs = new int[WIDTH];
        boolean isStop;
        //扫描上边距不等于背景颜色的第一个点
        for (int y = 0; y < HEIGHT; y++) {
            bp.getPixels(pixs, 0, WIDTH, 0, y, WIDTH, 1);
            isStop = false;
            for (int pix : pixs) {
                if (pix != mBGColor) {
                    top = y;
                    isStop = true;
                    break;
                }
            }
            if (isStop) {
                break;
            }
        }
        //扫描下边距不等于背景颜色的第一个点
        for (int y = HEIGHT - 1; y >= 0; y--) {
            bp.getPixels(pixs, 0, WIDTH, 0, y, WIDTH, 1);
            isStop = false;
            for (int pix : pixs) {
                if (pix != mBGColor) {
                    bottom = y;
                    isStop = true;
                    break;
                }
            }
            if (isStop) {
                break;
            }
        }
        pixs = new int[HEIGHT];
        //扫描左边距不等于背景颜色的第一个点
        for (int x = 0; x < WIDTH; x++) {
            bp.getPixels(pixs, 0, 1, x, 0, 1, HEIGHT);
            isStop = false;
            for (int pix : pixs) {
                if (pix != mBGColor) {
                    left = x;
                    isStop = true;
                    break;
                }
            }
            if (isStop) {
                break;
            }
        }
        //扫描右边距不等于背景颜色的第一个点
        for (int x = WIDTH - 1; x > 0; x--) {
            bp.getPixels(pixs, 0, 1, x, 0, 1, HEIGHT);
            isStop = false;
            for (int pix : pixs) {
                if (pix != mBGColor) {
                    right = x;
                    isStop = true;
                    break;
                }
            }
            if (isStop) {
                break;
            }
        }
        if (blankWidth < 0) {
            blankWidth = 0;
        }
        //计算加上保留空白距离之后的图像大小
        left = left - blankWidth > 0 ? left - blankWidth : 0;
        top = top - blankWidth > 0 ? top - blankWidth : 0;
        right = right + blankWidth > WIDTH - 1 ? WIDTH - 1 : right + blankWidth;
        bottom = bottom + blankWidth > HEIGHT - 1 ? HEIGHT - 1 : bottom + blankWidth;
        return Bitmap.createBitmap(bp, left, top, right - left, bottom - top);
    }

    /**
     * 设置画笔颜色
     *
     * @param color
     */
    public void setPaintColor(int color) {
        this.mPaintColor = color;
        if (null != mPaint) {
            mPaint.setColor(color);
        }
    }

    /**
     * 设置画笔宽度
     *
     * @param width
     */
    public void setPaintWidth(int width) {
        this.mPaintWidth = width > 0 ? width : 1;
        if (null != mPaint) {
            mPaint.setStrokeWidth(width);
        }
    }

    /**
     * 设置背景颜色
     */
    public void setBGColor(int color) {
        this.mBGColor = color;
    }

    /**
     * 是否有签名
     */
    public boolean hasSignature() {
        return mIsPainting;
    }

    /**
     * 设置图层
     *
     * @param map
     */
    public void setBitmap(Bitmap map) {
        mLastTimeBitmap = map;
        if (mHasSizeChanged) {
            mCacheCanvas.drawBitmap(mLastTimeBitmap, 0, 0, mPaint);
            mIsPainting = true;
            invalidate();
        }
    }

}
